package com.demo.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.demo.mapper.ClassroomMapper;
import com.demo.mapper.ClazzMapper;
import com.demo.mapper.CourseMapper;
import com.demo.mapper.ScheduleMapper;
import com.demo.mapper.TimeSlotMapper;
import com.demo.pojo.entity.Classroom;
import com.demo.pojo.entity.Clazz;
import com.demo.pojo.entity.Course;
import com.demo.pojo.entity.Schedule;
import com.demo.pojo.entity.TimeSlot;
import com.demo.service.IntelligentScheduleService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 简单排课服务实现类
 */
public class SimpleScheduleServiceImpl implements IntelligentScheduleService {
    
    @Autowired
    private ScheduleMapper scheduleMapper;
    
    @Autowired
    private CourseMapper courseMapper;
    
    @Autowired
    private ClassroomMapper classroomMapper;
    
    @Autowired
    private TimeSlotMapper timeSlotMapper;
    
    @Autowired
    private ClazzMapper clazzMapper;
    
    @Override
    public boolean executeIntelligentSchedule(String semester) {
        try {
            System.out.println("开始执行简单排课，学期：" + semester);
            
            // 1. 获取所有课程
            List<Course> courses = courseMapper.selectList(null);
            if (courses.isEmpty()) {
                System.out.println("没有找到课程数据");
                return false;
            }
            System.out.println("找到课程数量：" + courses.size());
            
            // 2. 获取可用教室
            QueryWrapper<Classroom> classroomQuery = new QueryWrapper<>();
            classroomQuery.eq("status", 1);
            List<Classroom> classrooms = classroomMapper.selectList(classroomQuery);
            if (classrooms.isEmpty()) {
                System.out.println("没有找到可用教室");
                return false;
            }
            System.out.println("找到教室数量：" + classrooms.size());
            
            // 3. 获取可用时间段
            QueryWrapper<TimeSlot> timeSlotQuery = new QueryWrapper<>();
            timeSlotQuery.eq("semester", semester).eq("status", 1);
            List<TimeSlot> timeSlots = timeSlotMapper.selectList(timeSlotQuery);
            if (timeSlots.isEmpty()) {
                System.out.println("没有找到可用时间段，学期：" + semester);
                return false;
            }
            System.out.println("找到时间段数量：" + timeSlots.size());
            
            // 4. 获取可用班级
            List<Clazz> clazzes = clazzMapper.selectList(null);
            if (clazzes.isEmpty()) {
                System.out.println("没有找到班级数据");
                return false;
            }
            System.out.println("找到班级数量：" + clazzes.size());
            
            // 5. 为每个课程分配教室、时间段和班级（支持多个班级批量排课）
            Random random = new Random();
            int successCount = 0;
            // 记录每个班本周已安排的节数，保证≤12
            Map<Long, Integer> clazzWeeklyCount = new HashMap<>();
            
            for (int i = 0; i < courses.size(); i++) {
                Course course = courses.get(i);
                
                // 检查课程是否有指定的教师
                if (course.getTeacherId() == null) {
                    System.out.println("课程 " + course.getCourseName() + " 没有指定教师，跳过排课");
                    continue;
                }
                
                // 根据课程类型选择合适的教室
                Classroom classroom = selectSuitableClassroom(course, classrooms, random);
                if (classroom == null) {
                    System.out.println("课程 " + course.getCourseName() + " 没有合适的教室，跳过排课");
                    continue;
                }
                
                // 根据课程与院系统配获取一组备选班级
                List<Clazz> eligibleClazzes = clazzes.stream()
                        .filter(cz -> course.getDept() == null || course.getDept().equals(cz.getDept()))
                        .collect(Collectors.toList());
                if (eligibleClazzes.isEmpty()) eligibleClazzes = clazzes;

                for (Clazz clazz : eligibleClazzes) {
                    // 🔒 固定每门课每个班每周排2节
                    int sessionsPerWeek = 2;
                    System.out.println("课程 [" + course.getCourseName() + "] 班级 [" + clazz.getClazzName() + 
                                     "] 固定每周安排: " + sessionsPerWeek + "节");
                    Set<Long> usedTimeSlotIds = new HashSet<>();
                    int actualScheduled = 0; // 统计实际排课数

                    for (int sessionIndex = 0; sessionIndex < sessionsPerWeek; sessionIndex++) {
                        // 班级总课时上限（≤12）
                        int current = clazzWeeklyCount.getOrDefault(clazz.getClazzId(), 0);
                        if (current >= 12) {
                            System.out.println("⚠️ 班级 [" + clazz.getClazzName() + "] 已达到每周12节上限，停止排课");
                            break;
                        }
                        boolean placed = false;
                        int maxAttempts = 30;
                        for (int attempt = 0; attempt < maxAttempts; attempt++) {
                            // 随机选择时间段与教室并做冲突校验
                            TimeSlot ts = timeSlots.get(random.nextInt(timeSlots.size()));
                            if (usedTimeSlotIds.contains(ts.getTimeSlotId())) continue; // 避免同一课程同一班重复同一时段

                            Classroom roomTry = classroom;
                            // 若首选教室类型匹配失败，适当再随机一次教室
                            if (random.nextBoolean()) {
                                roomTry = classrooms.get(random.nextInt(classrooms.size()));
                            }

                            if (!hasConflict(course.getTeacherId(), clazz.getClazzId(), roomTry.getClassroomId(), ts.getTimeSlotId())) {
                                // 创建排课记录
                                Schedule schedule = new Schedule();
                                schedule.setCourseId(course.getCourseId());
                                schedule.setTeacherId(course.getTeacherId());
                                schedule.setClassroomId(roomTry.getClassroomId());
                                schedule.setTimeSlotId(ts.getTimeSlotId());
                                schedule.setClazzId(clazz.getClazzId());
                                schedule.setScheduleType("正常");
                                schedule.setStatus("ACTIVE");
                                schedule.setPriority(3);
                                schedule.setIsFixed(0);
                                schedule.setCreateTime(new Date());
                                schedule.setUpdateTime(new Date());
                                try {
                                    scheduleMapper.insert(schedule);
                                    successCount++;
                                    actualScheduled++; // 计数
                                    usedTimeSlotIds.add(ts.getTimeSlotId());
                                    clazzWeeklyCount.put(clazz.getClazzId(), clazzWeeklyCount.getOrDefault(clazz.getClazzId(), 0) + 1);
                                    placed = true;
                                    System.out.println("  ✓ 成功排课第" + (sessionIndex + 1) + "/" + sessionsPerWeek + "节：" + 
                                                     course.getCourseName() + " -> " + clazz.getClazzName() + 
                                                     " -> " + roomTry.getClassroomName() + " -> " + ts.getTimeRemark());
                                    break;
                                } catch (Exception e) {
                                    // 入库失败则继续尝试
                                }
                            }
                        }
                        if (!placed) {
                            System.out.println("  ✗ 第" + (sessionIndex + 1) + "节排课失败：已尝试" + maxAttempts + "次");
                        }
                    }
                    
                    // 输出排课结果总结
                    if (actualScheduled < sessionsPerWeek) {
                        System.out.println("⚠️⚠️⚠️ 课程 [" + course.getCourseName() + "] 班级 [" + clazz.getClazzName() + "] 排课不完整！" +
                                         " 应排: " + sessionsPerWeek + "节，实际排: " + actualScheduled + "节 ⚠️⚠️⚠️");
                    } else {
                        System.out.println("✓✓✓ 课程 [" + course.getCourseName() + "] 班级 [" + clazz.getClazzName() + "] 排课完成！" +
                                         " 应排: " + sessionsPerWeek + "节，实际排: " + actualScheduled + "节 ✓✓✓");
                    }
                }
            }
            
            System.out.println("简单排课完成，成功创建排课数量：" + successCount);
            return successCount > 0;
            
        } catch (Exception e) {
            System.err.println("简单排课执行失败：" + e.getMessage());
            e.printStackTrace();
            return false;
        }
    }
    
    @Override
    public boolean checkConstraints(Schedule schedule) {
        return true; // 简化实现
    }
    
    @Override
    public List<Schedule> optimizeSchedule(List<Schedule> schedules) {
        return schedules; // 简化实现
    }
    
    @Override
    public boolean resolveConflicts(List<Schedule> schedules) {
        return true; // 简化实现
    }
    
    @Override
    public double calculateScheduleQuality(List<Schedule> schedules) {
        return 0.8; // 简化实现
    }
    
    /**
     * 根据课程类型选择合适的教室
     */
    private Classroom selectSuitableClassroom(Course course, List<Classroom> classrooms, Random random) {
        // 根据课程类型选择合适的教室类型
        String preferredType = getPreferredClassroomType(course);
        
        // 优先选择匹配类型的教室
        List<Classroom> suitableClassrooms = classrooms.stream()
                .filter(classroom -> preferredType.equals(classroom.getClassroomType()))
                .collect(Collectors.toList());
        
        // 如果没有匹配的教室类型，使用普通教室
        if (suitableClassrooms.isEmpty()) {
            suitableClassrooms = classrooms.stream()
                    .filter(classroom -> "普通教室".equals(classroom.getClassroomType()))
                    .collect(Collectors.toList());
        }
        
        // 如果还是没有，使用任何可用教室
        if (suitableClassrooms.isEmpty()) {
            suitableClassrooms = classrooms;
        }
        
        return suitableClassrooms.get(random.nextInt(suitableClassrooms.size()));
    }
    
    /**
     * 根据课程类型获取推荐的教室类型
     */
    private String getPreferredClassroomType(Course course) {
        String courseName = course.getCourseName().toLowerCase();
        String dept = course.getDept();
        
        // 计算机相关课程优先使用机房
        if (courseName.contains("程序") || courseName.contains("编程") || 
            courseName.contains("软件") || courseName.contains("算法") ||
            courseName.contains("数据库") || courseName.contains("网络") ||
            courseName.contains("机器学习") || courseName.contains("人工智能")) {
            return "机房";
        }
        
        // 物理实验课程使用实验室
        if (courseName.contains("物理") || courseName.contains("实验")) {
            return "实验室";
        }
        
        // 语言类课程使用语音室
        if (courseName.contains("英语") || courseName.contains("日语") || 
            courseName.contains("语言") || courseName.contains("口语")) {
            return "语音室";
        }
        
        // 艺术类课程使用画室
        if (courseName.contains("美术") || courseName.contains("绘画") || 
            courseName.contains("设计") || courseName.contains("艺术")) {
            return "画室";
        }
        
        // 其他课程使用普通教室或多媒体教室
        return "多媒体教室";
    }
    
    /**
     * 根据课程选择合适的班级
     */
    private Clazz selectSuitableClass(Course course, List<Clazz> clazzes, Random random) {
        // 根据课程所属院系选择合适的班级
        String courseDept = course.getDept();
        
        // 优先选择同院系的班级
        List<Clazz> suitableClazzes = clazzes.stream()
                .filter(clazz -> courseDept.equals(clazz.getDept()))
                .collect(Collectors.toList());
        
        // 如果没有同院系的班级，使用任何班级
        if (suitableClazzes.isEmpty()) {
            suitableClazzes = clazzes;
        }
        
        return suitableClazzes.get(random.nextInt(suitableClazzes.size()));
    }
    
    /**
     * 选择合适的时间段（避免冲突）
     */
    private TimeSlot selectSuitableTimeSlot(Course course, List<TimeSlot> timeSlots, Random random) {
        // 简化实现：随机选择一个时间段
        // 在实际应用中，这里应该检查教师时间冲突、教室时间冲突等
        return timeSlots.get(random.nextInt(timeSlots.size()));
    }

    /**
     * 基础冲突校验：同一时间段，教师/教室/班级任一冲突即不可用
     */
    private boolean hasConflict(Long teacherId, Long clazzId, Long classroomId, Long timeSlotId) {
        // 教师冲突
        QueryWrapper<Schedule> q1 = new QueryWrapper<>();
        q1.eq("teacher_id", teacherId).eq("time_slot_id", timeSlotId);
        if (scheduleMapper.selectCount(q1) > 0) return true;

        // 教室冲突
        QueryWrapper<Schedule> q2 = new QueryWrapper<>();
        q2.eq("classroom_id", classroomId).eq("time_slot_id", timeSlotId);
        if (scheduleMapper.selectCount(q2) > 0) return true;

        // 班级冲突
        QueryWrapper<Schedule> q3 = new QueryWrapper<>();
        q3.eq("clazz_id", clazzId).eq("time_slot_id", timeSlotId);
        return scheduleMapper.selectCount(q3) > 0;
    }
}


